//  WordsAppDelegate.m
//  Words
//
//  Created by Mathieu on 9/06/06.
//  Copyright __MyCompanyName__ 2006 . All rights reserved.


#import "WordsAppDelegate.h"
#import "MyServicesProvider.h"
#import "WordMO.h"
#import "WordUtilities.h"
#import "DictProtocolDictionary.h"
#import "DefinitionMO.h"
#import "Lookup.h"
#import "BubbleController.h"
#import "ControllerData.h"
#import "ImageMO.h";

#include <assert.h>
#include <unistd.h>

@implementation NSFileManager (PRAdditions)

- (NSString *)findSystemFolderType:(int)folderType forDomain:(int)domain
{
    FSRef folder;
    OSErr err = noErr;
    CFURLRef url;
    NSString *result = nil;
	
    err = FSFindFolder(domain, folderType, false, &folder);
    if (err == noErr) {
        url = CFURLCreateFromFSRef(kCFAllocatorDefault, &folder);
        result = [(NSURL *)url path];
    }
	
    return result;
}

@end 


@implementation WordsAppDelegate

#pragma mark Initialisers
-(void)awakeFromNib{

	[mainWindowTabView selectTabViewItemWithIdentifier:@"MainView"];
	//register for notifications
	[[NSNotificationCenter defaultCenter] addObserver:self 
											 selector:@selector(makeWindowActive:) 
												 name:NSApplicationDidBecomeActiveNotification object:nil];
}


- (void)makeWindowActive:(NSNotification *)notification{
	[window makeKeyAndOrderFront:nil];
}
- (void)applicationDidFinishLaunching:(NSNotification*)n
{
	MyServicesProvider *serviceObject = [[MyServicesProvider alloc] init]; //bring the service provideo object forth from the framework (class heirarchy)
	[NSApp setServicesProvider:serviceObject]; //give it to the NSApp object
	
	//get the selectionSaver from the managed object context
	// create the fetch request for the words
	NSError *error;
	NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
	[fetchRequest setEntity: [NSEntityDescription entityForName:@"ControllerData" inManagedObjectContext:[self managedObjectContext]]];
	NSArray *array = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
	if([array count] == 0){
		//create a new one
		controllerDataEntity = [NSEntityDescription insertNewObjectForEntityForName:@"ControllerData" inManagedObjectContext:[self managedObjectContext]];
		languageGroupControllerSelectionSaver = [controllerDataEntity languageGroupSelectionDictionary];
	}
	else{
		controllerDataEntity = [array objectAtIndex:0];
		languageGroupControllerSelectionSaver = [controllerDataEntity languageGroupSelectionDictionary];
	}
	//fetch it
	//If it's not there, create a new one
	//if there are no languages defined (probably the first time launched)
	//set up the fetch request

	NSError *fetchError = nil; 
	NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Language" inManagedObjectContext:[self managedObjectContext]]; 
	NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
	[request setEntity:entityDescription]; 
	NSArray *anyLanguages = [[self managedObjectContext] executeFetchRequest:request error:&fetchError]; 
	if([anyLanguages count] == 0){
		[mainWindowTabView selectTabViewItemWithIdentifier:@"AddLanguage"];
		[newLanguageInfoStringInAddLanguageView setHidden:NO];
	}
	
	NSMutableSet *internalDicts = [self internalDictionaries];
	
	//set up the lookup worker thread
	NSPort *port1 = [NSPort port];
    NSPort *port2 = [NSPort port];
    NSArray *portArray = nil;
    NSConnection* kitConnection = nil; 
    kitConnection = [[NSConnection alloc] initWithReceivePort:port1
													 sendPort:port2];
    [kitConnection setRootObject:self];
    // Ports switched here.
    portArray = [NSArray arrayWithObjects:port2, port1, nil];
    [NSThread detachNewThreadSelector:@selector(connectWithPorts:)
							 toTarget:[Lookup class] withObject:portArray];
    return;
		
}






- (void)setServer:(id)anObject
{
    [anObject setProtocolForProxy:@protocol(LookupMethods)];
	id look = (id <LookupMethods>)[anObject retain];
	lookerupperer = look;
	
    return;
}

- (LanguageMO *)currentlySelectedLanguage{
	if(languageArrayController != nil){
		if([[languageArrayController selectedObjects] count] != 0){
			return [[languageArrayController selectedObjects] objectAtIndex:0];
		}
	}else return nil;
}

- (LanguageMO *)currentlySelectedTransLanguage{
	return [[transLangArrayController selectedObjects] objectAtIndex:0];
}

- (Group *)currentlySelectedGroup{
	return [[groupArrayController selectedObjects] objectAtIndex:0];
}

- (InUseDictController *)inUseDictController{
	return inUseDictController;
}
- (void)setMainWindowTabToMainView{
	[mainWindowTabView selectTabViewItemWithIdentifier:@"MainView"];
}

#pragma mark Tab View selection

- (IBAction)returnToMainTab:(id)sender{
	[self setMainWindowTabToMainView];
}
- (IBAction)openGamesTab:(id)sender{
	[mainWindowTabView selectTabViewItemWithIdentifier:@"GameViewTab"];
}
- (IBAction)openLanguageAndContextCreatorTab:(id)sender{
	[mainWindowTabView selectTabViewItemWithIdentifier:@"NewLanguage"];
}

- (IBAction)openAlternativeViewTab:(id)sender{
	[mainWindowTabView selectTabViewItemWithIdentifier:@"AlternativeView"];
}

//accessor to the app's bubble controller object
-(BubbleController *)bubbleController{
	return bubbleController;
}
#pragma mark 'Internal' Dictionaries fupport
//returns an array of the internally supported Dictionaries.
-(NSMutableSet *)internalDictionaries{
	//open the folder with all the language archives in it
	NSArray *dictPathsArray = [[NSBundle mainBundle] pathsForResourcesOfType:@"wordsDict" inDirectory:nil];
	NSMutableSet *bagODicts = [[NSMutableSet alloc ] init];
		
	int i, count = [dictPathsArray count];
	for (i=0; i<count; i++) {
		NSString *aFile = [dictPathsArray objectAtIndex:i];
		DictionaryMO* dict = [NSKeyedUnarchiver unarchiveObjectWithFile:aFile];
		if(dict != nil){
			[bagODicts addObject:dict];
		}
	}
	return bagODicts;
}

//accessor for the dictionary that holds selection information for groups
- (NSMutableDictionary *)languageGroupControllerSelectionSaver{
	if(!languageGroupControllerSelectionSaver){
		languageGroupControllerSelectionSaver = [controllerDataEntity languageGroupSelectionDictionary];
	}
	return [[languageGroupControllerSelectionSaver retain] autorelease];
}

-(ControllerData *)controllerDataEntityAccess{
	return [[controllerDataEntity retain] autorelease];
}


#pragma mark Lookup and Dictionary Methods

-(IBAction)defineSelectedWord:(id)sender{
	/*this method takes the selected word and tries to find definitions for it in the provided dictionaries for the translangs. */
	NSArray *words = [allWords selectedObjects];
	NSArray *allDictionaries = [self transLangsDictionaries];
	NSEnumerator *e = [allDictionaries objectEnumerator];
	NSMutableArray *remoteDictionaries = [[NSMutableArray alloc] init];
	NSMutableArray *localDictionaries = [[NSMutableArray alloc] init];
	//construct the arrays of dicts according to whether they are remote or not.
	DictionaryMO *nextDict;
	while(nextDict = [e nextObject]){
		if([[nextDict valueForKey:@"isRemote"] isEqualToNumber:[NSNumber numberWithBool:YES]]){
			[remoteDictionaries addObject:nextDict];
		}
		else{
			[localDictionaries addObject:nextDict];
		}
	}
	
	[definitionInProgressIndicator setHidden:NO];
	[definitionInProgressIndicator startAnimation:nil];
	[[self lookerupperer] defineWords:words inDictionaries:[NSArray arrayWithArray:remoteDictionaries]]; //we don't want to pass a mutable object to a thead really.
	
	NSMutableDictionary *dashboard = nil;
	NSEnumerator *dictEnum = [localDictionaries objectEnumerator];
	WordMO *word;
	DictionaryMO* dict;
	NSString *capabilityKey;
	NSMutableString *definitionsBlob;
	while(dict = [dictEnum nextObject]){
		if([dict isAvailable]){
			NSEnumerator *wordEnum = [words objectEnumerator];
			capabilityKey = [dict valueForKey:@"targetLanguages"]; 
			NSLog(@"Looking up %@ definitions in %@", capabilityKey, [dict valueForKey:@"name"]); //report what we're doing
			
			while(word = [wordEnum nextObject]){
				NSLog(@"---- %@", [word valueForKey:@"word"]);
				if (![word isDefined]){ //if the next word is not defined already
					definitionsBlob = [dict stringBlobOfDefinitions:[word valueForKey:@"word"]]; //get a string blob of definitions the next word in the current dictionary;				
					if(definitionsBlob != nil){ //provided we have a definition to speak of
						dashboard = [[[NSMutableDictionary alloc] init] retain];
						NSAttributedString *attributedDef = [[[NSAttributedString alloc] initWithString:definitionsBlob] autorelease]; 
						[dashboard setValue:attributedDef forKey:[[[dict objectID] URIRepresentation] absoluteString]];
					} else{ NSLog(@"Nothing Found!"); }
				} else { NSLog(@"(Already Defined)"); }
				//package up this words dashboard and send it on it's way back to the main thread
				if(dashboard){		
					NSData *dashboardData = [NSKeyedArchiver archivedDataWithRootObject:dashboard];
					[word setValue:dashboardData forKey:@"dashboardData"];
					[dashboard release]; dashboard = nil;
				}
			}
		}else{ NSLog(@"Dictionary %@ Not Available. Did it become unavailable along the way somewhere?", [dict valueForKey:@"name"]); }
	}
	//clean up
	[[NSApp delegate] stopDefiningAllWordsAnimation];
	
	
}




-(NSArray *)transLangsDictionaries{
	//returns an array of dictionaries that are set to look up words in the trans languages
	NSArray *langs = [transLangArrayController arrangedObjects];
	NSMutableArray *alldicts = [[NSMutableArray alloc] init];
	NSEnumerator *e = [langs objectEnumerator];
	LanguageMO *nextLang;
	while(nextLang = [e nextObject]){
		[alldicts addObjectsFromArray:[[nextLang mutableSetValueForKey:@"dictionaries"] allObjects]];
	}
	return [NSArray arrayWithArray:alldicts];
	
}

//This method is called by the seach controller to quickly look up definitions in real time as they are typed (yes, we're going to give this a go!)
//Returns a YES if there was something found
-(bool)defineWord:(WordMO*)word{
	bool result = NO;
	NSArray *allDictionaries = [inUseDictController arrangedObjects]; //gets the dictionaries set up to be in use by the currently selected language.
	NSEnumerator *e = [allDictionaries objectEnumerator];
	NSMutableArray *remoteDictionaries = [[NSMutableArray alloc] init];
	NSMutableArray *localDictionaries = [[NSMutableArray alloc] init];
	
	//construct the arrays of dicts according to whether they are remote or not. 
	//We chuck away the remote dictionaries, because they take too bloody long. 
	DictionaryMO *nextDict;
	while(nextDict = [e nextObject]){
		if([[nextDict valueForKey:@"isRemote"] isEqualToNumber:[NSNumber numberWithBool:YES]]){
			[remoteDictionaries addObject:nextDict];
		}
		else{
			[localDictionaries addObject:nextDict];
		}
	}
	
	[definitionInProgressIndicator setHidden:NO];
	[definitionInProgressIndicator startAnimation:nil];
	
	NSMutableDictionary *dashboard = nil;
	NSEnumerator *dictEnum = [localDictionaries objectEnumerator];
	DictionaryMO* dict;
	NSString *capabilityKey;
	NSMutableString *definitionsBlob;
	while(dict = [dictEnum nextObject]){
		if([dict isAvailable]){
			capabilityKey = [dict valueForKey:@"targetLanguages"]; 
			NSLog(@"Looking up %@ definitions in %@", capabilityKey, [dict valueForKey:@"name"]); //report what we're doing
				NSLog(@"---- %@", [word valueForKey:@"word"]);
				if (![word isDefined]){ //if the next word is not defined already
					definitionsBlob = [dict stringBlobOfDefinitions:[word valueForKey:@"word"]]; //get a string blob of definitions the next word in the current dictionary;				
					if(definitionsBlob != nil){ //provided we have a definition to speak of
						result = YES;
						dashboard = [[[NSMutableDictionary alloc] init] retain];
						NSAttributedString *attributedDef = [[[NSAttributedString alloc] initWithString:definitionsBlob] autorelease]; 
						[dashboard setValue:attributedDef forKey:[[[dict objectID] URIRepresentation] absoluteString]];
					} else{ NSLog(@"Nothing Found!"); }
				} else { NSLog(@"(Already Defined)"); }
				//package up this words dashboard and send it on it's way back to the main thread
				if(dashboard){		
					NSData *dashboardData = [NSKeyedArchiver archivedDataWithRootObject:dashboard];
					[word setValue:dashboardData forKey:@"dashboardData"];
					[dashboard release]; dashboard = nil;
				}
		}else{ NSLog(@"Dictionary %@ Not Available. Did it become unavailable along the way somewhere?", [dict valueForKey:@"name"]); }
	}
	//clean up
	[[NSApp delegate] stopDefiningAllWordsAnimation];
	return result;
	
}

-(IBAction)defineAllWords:(id)sender{
	//perhaps it's more intelligent to divide up the serach into dictionaries that are remote and not remote, because
	//dictionaries that take a lot of time are remote... and it would also be more convenient because 
	//local sratdicts aren't threading well... and it's not really beneficial to do so anyway, in fact, if they're
	//intermingled with dictionaries that take a long time, then they have to block and wait ANYWAY which is rubbish.
	NSArray *words = [wordArrayController arrangedObjects];
	
	NSArray *allDictionaries = [inUseDictController arrangedObjects];
	NSEnumerator *e = [allDictionaries objectEnumerator];
	NSMutableArray *remoteDictionaries = [[NSMutableArray alloc] init];
	NSMutableArray *localDictionaries = [[NSMutableArray alloc] init];
	//construct the arrays of dicts according to whether they are remote or not.
	DictionaryMO *nextDict;
	while(nextDict = [e nextObject]){
		if([[nextDict valueForKey:@"isRemote"] isEqualToNumber:[NSNumber numberWithBool:YES]]){
			[remoteDictionaries addObject:nextDict];
		}
		else{
			[localDictionaries addObject:nextDict];
		}
	}

	[definitionInProgressIndicator setHidden:NO];
	[definitionInProgressIndicator startAnimation:nil];
	[[self lookerupperer] defineWords:words inDictionaries:[NSArray arrayWithArray:remoteDictionaries]]; //we don't want to pass a mutable object to a thead really.
	
	NSMutableDictionary *dashboard = nil;
	NSEnumerator *dictEnum = [localDictionaries objectEnumerator];
	WordMO *word;
	DictionaryMO* dict;
	NSString *capabilityKey;
	NSMutableString *definitionsBlob;
	while(dict = [dictEnum nextObject]){
		if([dict isAvailable]){
			NSEnumerator *wordEnum = [words objectEnumerator];
			capabilityKey = [dict valueForKey:@"targetLanguages"]; 
			NSLog(@"Looking up %@ definitions in %@", capabilityKey, [dict valueForKey:@"name"]); //report what we're doing
			
			while(word = [wordEnum nextObject]){
				NSLog(@"---- %@", [word valueForKey:@"word"]);
				if (![word isDefined]){ //if the next word is not defined already
					definitionsBlob = [dict stringBlobOfDefinitions:[word valueForKey:@"word"]]; //get a string blob of definitions the next word in the current dictionary;				
					if(definitionsBlob != nil){ //provided we have a definition to speak of
						dashboard = [[[NSMutableDictionary alloc] init] retain];
						NSAttributedString *attributedDef = [[[NSAttributedString alloc] initWithString:definitionsBlob] autorelease]; 
						[dashboard setValue:attributedDef forKey:[[[dict objectID] URIRepresentation] absoluteString]];
					} else{ NSLog(@"Nothing Found!"); }
				} else { NSLog(@"(Already Defined)"); }
				//package up this words dashboard and send it on it's way back to the main thread
				if(dashboard){		
					NSData *dashboardData = [NSKeyedArchiver archivedDataWithRootObject:dashboard];
					[word setValue:dashboardData forKey:@"dashboardData"];
					[dashboard release]; dashboard = nil;
				}
			}
		}else{ NSLog(@"Dictionary %@ Not Available. Did it become unavailable along the way somewhere?", [dict valueForKey:@"name"]); }
	}
	//clean up
	[[NSApp delegate] stopDefiningAllWordsAnimation];
	
}



-(void)stopDefiningAllWordsAnimation{
	[definitionInProgressIndicator stopAnimation:nil];
	[definitionInProgressIndicator setHidden:YES];
}

//Takes all words in current word list and attempts to define each one for the dictionaries available to the language.
-(IBAction)attemptToDefineAllWordsInWordArray:(id)sender{
	
	NSSet *setOfDicts = [self inUseDictionariesForLanguage:[self currentlySelectedLanguage]];
	if([setOfDicts count] == 0){
		NSLog(@"No dictionaries Set");
		//tell the definitions view to set itself to display NoDictionariesSet; or something like that.
		[definitionsTabView selectTabViewItemAtIndex:1];
	}
	else{
		[definitionsTabView selectTabViewItemAtIndex:0];
		NSArray *allWordsInCurrentView = [wordArrayController arrangedObjects]; // the words we want to define
		[self define:allWordsInCurrentView];
	}
}


//returns an array with the dictionary objects that are 'inUse' by a language for defining words.
-(NSSet *)inUseDictionariesForLanguage:(LanguageMO *)language{
	NSSet *setOfDicts = [language mutableSetValueForKey:@"dictionaries"];
	// lets the user know if there are no dictionaries set to be 'in use'
	
	return setOfDicts;
}

//accessor for the lookup threaded object
-(id)lookerupperer{
	return [[lookerupperer retain] autorelease];
}


#pragma mark Delegates
//reacts to notification from table view to update
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification{
	
	NSString *formattedString = [NSString stringWithFormat:@"%u Words", [[wordArrayController arrangedObjects] count]];
	
	[windowSummaryString setStringValue:formattedString];
}

#pragma mark export to sql

/* Formatting guide:*/
/*LANGUAGES

insert into language (LANGID, CREATIONTIMESTAMP)
values
('eng', (select CURRENT_TIMESTAMP FROM DUAL));
*/
-(IBAction)exportLanguagesToSQL:(id)sender{
	NSError *e;
	NSFetchRequest *request = [[NSFetchRequest alloc] init];
	[request setEntity:[NSEntityDescription entityForName:@"Language" inManagedObjectContext:[self managedObjectContext]]];
	NSArray *langs = [[self managedObjectContext] executeFetchRequest:request error:&e];
	//NSLog(@"Exporting Languages: %@", langs);
	
	NSEnumerator *langEnum = [langs objectEnumerator];
	LanguageMO *nextLang;
	NSString *sqlString = [NSString stringWithString:@"\n"];
	while(nextLang = [langEnum nextObject]){
		sqlString = [sqlString stringByAppendingFormat:@"EXECUTE newLanguage('%@');\n", [nextLang valueForKey:@"capability"]]; 
	}
	NSLog(@"%@", sqlString);
	
	
}

// Dump everything
-(IBAction)exportWordsAndDefsToSQLOfSelectedLanguage:(id)sender{
	NSString * sqlString = [NSString stringWithString:@"\n"];
	NSArray *langsToExport = [languageArrayController arrangedObjects];
	NSEnumerator *langEnum = [langsToExport objectEnumerator];
	LanguageMO *lang;
	while(lang = [langEnum nextObject]){
		NSString *langID = [lang valueForKey:@"capability"];
		//NSLog(@"Exporting words and defs from language: %@", lang);
		NSMutableSet *words = [lang mutableSetValueForKey:@"words"];
		NSMutableSet *defs;
		NSMutableSet *images;
		NSMutableSet *blobs;
		//NSMutableSet *recordings;
		NSEnumerator *wordEnum = [words objectEnumerator];
		NSEnumerator *defEnum;
		WordMO *nextWord;
		id nextDef;
		while(nextWord = [wordEnum nextObject]){
			//insert the word
			sqlString = [sqlString stringByAppendingFormat:@"EXECUTE addNewFreshWord('%@', '%@');\n", langID, [nextWord valueForKey:@"word"]]; 
			//insert the word's defs and blobs, images and recordings
			defs = [nextWord mutableSetValueForKey:@"definitions"];
			defEnum = [defs objectEnumerator];
			while(nextDef = [defEnum nextObject]){				//definitions
				NSString *type = [nextDef valueForKey:@"type"];
				if([type isEqualToString:@"NA"]){
					type = [NSString stringWithString:@"NULL"];
				}
				sqlString = [sqlString stringByAppendingFormat:@"EXECUTE addNewFreshDefinitionAfterWord('%@', '%@');\n", [nextDef valueForKey:@"capabilityKey"], [nextDef valueForKey:@"definition"]]; 
			}
			images = [nextWord mutableSetValueForKey:@"images"];
			defEnum = [images objectEnumerator];
			while(nextDef = [defEnum nextObject]){				//images
				sqlString = [sqlString stringByAppendingFormat:@"EXECUTE addNewFreshImageAfterWord('%@', '%@');\n", [nextDef valueForKey:@"webURL"], [nextDef valueForKey:@"name"]];
			}
			blobs = [nextWord mutableSetValueForKey:@"blobs"];
			defEnum = [blobs objectEnumerator];
			while(nextDef = [defEnum nextObject]){				//blobs
				NSAttributedString *textBlob = [nextDef textBlob];
				sqlString = [sqlString stringByAppendingFormat:@"EXECUTE addNewFreshBlobAfterWord('%@', '%@', '%@');\n", [nextDef valueForKey:@"capabilityKey"], textBlob, [nextDef valueForKey:@"source"]];
				
			}
		}
		NSLog(@"%@", sqlString);
		sqlString = [NSString stringWithString:@"\n"];
	}

}

/*WORDS

insert into word (wordID, langID, word, creationTimeStamp, lastModified, requestCount, instanceCount, submitCount, type, validationMetric, completenessLevel)
values (wordIDSeq.nextval, 'eng', 'cookie', (select CURRENT_TIMESTAMP FROM DUAL), (select CURRENT_TIMESTAMP FROM DUAL), NULL, 1, 0, NULL, NULL, NULL);
*/
/*DEFINITIONS
insert into definition
values (definitionIDSeq.nextval, 2, 'eng', 'What americans usually call a biscuit.', NULL, (select CURRENT_TIMESTAMP FROM DUAL), 0, 1, 0);
*/

//These methods aim to export all the user's data into oracle formatted sql.

#pragma mark Core Data Stuff
- (NSManagedObjectModel *)managedObjectModel {
    if (managedObjectModel) return managedObjectModel;
	
	NSMutableSet *allBundles = [[NSMutableSet alloc] init];
	[allBundles addObject: [NSBundle mainBundle]];
	[allBundles addObjectsFromArray: [NSBundle allFrameworks]];
    
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles: [allBundles allObjects]] retain];
    [allBundles release];
    
    return managedObjectModel;
}

/* Change this path/code to point to your App's data store. */
- (NSString *)applicationSupportFolder {
    NSString *applicationSupportFolder = nil;
    FSRef foundRef;
    OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kDontCreateFolder, &foundRef);
    if (err != noErr) {
        NSRunAlertPanel(@"Alert", @"Can't find application support folder", @"Quit", nil, nil);
        [[NSApplication sharedApplication] terminate:self];
    } else {
        unsigned char path[1024];
        FSRefMakePath(&foundRef, path, sizeof(path));
        applicationSupportFolder = [NSString stringWithUTF8String:(char *)path];
        applicationSupportFolder = [applicationSupportFolder stringByAppendingPathComponent:@"Words"];
    }
    return applicationSupportFolder;
}

- (NSManagedObjectContext *) managedObjectContext {
    NSError *error;
    NSString *applicationSupportFolder = nil;
    NSURL *url;
    NSFileManager *fileManager;
    NSPersistentStoreCoordinator *coordinator;
    
    if (managedObjectContext) {
        return managedObjectContext;
    }
    
    fileManager = [NSFileManager defaultManager];
    applicationSupportFolder = [self applicationSupportFolder];
    if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
        [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
    }
    
	url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"Words.xml"]];
//  url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"Words.sql"]];
    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    if ([coordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:nil error:&error]){
        managedObjectContext = [[NSManagedObjectContext alloc] init]; //NSSQLiteStoreType
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    } else {
        [[NSApplication sharedApplication] presentError:error];
    }    
    [coordinator release];
    
    return managedObjectContext;
}

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
    return [[self managedObjectContext] undoManager];
}

- (IBAction) saveAction:(id)sender {
    NSError *error = nil;
    if (![[self managedObjectContext] save:&error]) {
        [[NSApplication sharedApplication] presentError:error];
    }
}

- (void) cleanOutUnwantedImages{
	//fetch all the unflagged photos from the users database and can em'
	NSError *fetchError = nil; 
	NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Image" inManagedObjectContext:[self managedObjectContext]]; 
	NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
	[request setEntity:entityDescription]; 
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"keep = NO"];
	[request setPredicate:predicate];
	NSArray *unflaggedImages = [[self managedObjectContext] executeFetchRequest:request error:&fetchError];
	ImageMO *image;
	NSEnumerator *e = [unflaggedImages objectEnumerator];
	while (image = [e nextObject]){
		[[self managedObjectContext] deleteObject:image];
	}
}

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {

	
//	[self cleanOutUnwantedImages];
    NSError *error;
    NSManagedObjectContext *context;
    int reply = NSTerminateNow;
    
    context = [self managedObjectContext];
    if (context != nil) {
        if ([context commitEditing]) {
            if (![context save:&error]) {
				
				// This default error handling implementation should be changed to make sure the error presented includes application specific error recovery. For now, simply display 2 panels.
                BOOL errorResult = [[NSApplication sharedApplication] presentError:error];
				
				if (errorResult == YES) { // Then the error was handled
					reply = NSTerminateCancel;
				} else {
					
					// Error handling wasn't implemented. Fall back to displaying a "quit anyway" panel.
					int alertReturn = NSRunAlertPanel(nil, @"Could not save changes while quitting. Quit anyway?" , @"Quit anyway", @"Cancel", nil);
					if (alertReturn == NSAlertAlternateReturn) {
						reply = NSTerminateCancel;	
					}
				}
            }
        } else {
            reply = NSTerminateCancel;
        }
    }
	
	//fetch the controllerData entity again from Context
	NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
	[fetchRequest setEntity: [NSEntityDescription entityForName:@"ControllerData" inManagedObjectContext:context]];
	NSArray *array = [context executeFetchRequest:fetchRequest error:&error];
	if([array count] == 0){
		NSLog(@"computer says no.");
	}
	else{
		controllerDataEntity = [array objectAtIndex:0];
		[controllerDataEntity setLanguageGroupSelectionDictionary:languageGroupControllerSelectionSaver];
	}
	
    return reply;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
	return [[persistentStoreCoordinator retain] autorelease];
}

@end
